#pragma once

#include <mcp/config.h>
#include <mcp/forward.h>
#include <mcp/json/value.h>

#include <stdexcept>
#include <string>
#include <system_error>

namespace mcp {

/// @brief MCP error codes following JSON-RPC and MCP specification
enum class ErrorCode {
    // Standard JSON-RPC errors
    ParseError = -32700,
    InvalidRequest = -32600,
    MethodNotFound = -32601,
    InvalidParams = -32602,
    InternalError = -32603,

    // MCP specific errors
    Unauthorized = -32001,
    Forbidden = -32003,
    NotFound = -32004,
    Conflict = -32009,
    ResourceConflict = -32010,
    UnsupportedOperation = -32011,
    RequestTimeout = -32008,
    ProtocolError = -32000,

    // Validation errors
    InvalidUri = -32701,
    InvalidSchema = -32702,
    ValidationFailed = -32703
};

/// @brief MCP error class
class Error : public std::exception {
public:
    Error(ErrorCode code, std::string message);
    Error(ErrorCode code, std::string message, mcp::json::optional<json::Value> data);

    // Accessors
    ErrorCode code() const noexcept { return code_; }
    const std::string& message() const noexcept { return message_; }
    const mcp::json::optional<json::Value>& data() const noexcept { return data_; }

    // std::exception interface
    const char* what() const noexcept override;

    // Factory methods for common errors
    static Error parse_error(std::string message);
    static Error invalid_request(std::string message);
    static Error method_not_found(std::string method);
    static Error invalid_params(std::string message);
    static Error internal_error(std::string message);
    static Error unauthorized(std::string message);
    static Error forbidden(std::string message);
    static Error not_found(std::string resource);
    static Error conflict(std::string message);
    static Error unsupported_operation(std::string operation);
    static Error timeout(std::string message);
    static Error protocol_error(std::string message);

private:
    ErrorCode code_;
    std::string message_;
    mcp::json::optional<json::Value> data_;
    mutable std::string full_message_;
};

/// @brief Result type for operations that can fail
template<typename T>
using Result = mcp::json::expected<T, mcp::Error>;

/// @brief Error category for MCP errors
class ErrorCategory : public std::error_category {
public:
    const char* name() const noexcept override;
    std::string message(int ev) const override;
    std::error_condition default_error_condition(int ev) const noexcept override;
};

/// @brief Get the MCP error category
const ErrorCategory& mcp_error_category() noexcept;

/// @brief Make error code from ErrorCode
std::error_code make_error_code(ErrorCode e) noexcept;

/// @brief Make error condition from ErrorCode
std::error_condition make_error_condition(ErrorCode e) noexcept;

// Support for implicit conversion to std::error_code
inline std::error_code make_error_code(ErrorCode e) noexcept {
    return std::error_code(static_cast<int>(e), mcp_error_category());
}

} // namespace mcp

// Enable ErrorCode to be used with std::error_code
template<>
struct std::is_error_code_enum<mcp::ErrorCode> : std::true_type {};